package com.example.demo.Interceptor;


import com.example.demo.utils.RequestUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.TypeMismatchException;
import org.springframework.http.HttpStatus;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.multipart.MultipartException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import java.sql.SQLException;
import java.util.stream.Collectors;

/**
 * 异常拦截器
 *
 * https://jishuin.proginn.com/p/763bfbd60e57
 *
 * @author : YZD
 * @date : 2021-7-28 16:16
 */
@ResponseBody
@ControllerAdvice
@ResponseStatus(HttpStatus.OK)
public class GlobalExceptionHandler {

    private final Logger log = LoggerFactory.getLogger(this.getClass());

    @ExceptionHandler(value = BzException.class)
    public ResponseEntity<Void> handlerBzException(BzException e) {
        log.error("业务异常:{}", e.getMessage());
        return ResponseEntity.error(e.getStatus(), e.getMessage());
    }

    @ExceptionHandler(value = ConstraintViolationException.class)
    public ResponseEntity<String> handleValidException(ConstraintViolationException e) {
        String message = e.getConstraintViolations()
                .stream().
                        map(ConstraintViolation::getMessage)
                .collect(Collectors.joining(" "));
        log.error("参数不正确:{}", e.getMessage());
        return ResponseEntity.error(ResponseEnum.PARAM_ERROR.getStatus(), message);
    }


    @ExceptionHandler(MissingServletRequestParameterException.class)
    @ResponseBody
    public ResponseEntity<String> paramException(MissingServletRequestParameterException ex) {
        log.error("缺少请求参数:{}", ex.getMessage());
        return ResponseEntity.builderResponse(407, "缺少参数:" + ex.getParameterName(), null);
    }

    @ExceptionHandler(MultipartException.class)
    @ResponseBody
    public ResponseEntity<String> fileSizeLimit(MultipartException e) {
        log.error("超过文件大小限制,最大100MB");
        return ResponseEntity.builderResponse(506, "超过文件大小限制,最大100MB", null);
    }

    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    @ResponseBody
    public ResponseEntity<String> requestMethod(HttpRequestMethodNotSupportedException ex) {
        log.error("请求方式有误：{}", ex.getMethod());
        return ResponseEntity.builderResponse(405, "请求方式有误:" + ex.getMethod(), null);
    }

    @ResponseBody
    @ExceptionHandler(SQLException.class)
    public ResponseEntity<String> sqlException(HttpServletRequest req, HttpServletResponse rsp, Exception ex) {
        log.error("请求地址:{} 来自 {} sql exception:{}", req.getRequestURI(), RequestUtil.getIpAddress(req), ex);
        return ResponseEntity.builderResponse(504, ex == null ? null : ex.getMessage(), null);
    }

    @ResponseBody
    @ResponseStatus(code = HttpStatus.NOT_FOUND)
    @ExceptionHandler(NoHandlerFoundException.class)
    public ResponseEntity<String> notFound(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception {
        log.error("请求地址 :{} 来自IP {} 404:{}", request.getRequestURI(), RequestUtil.getIpAddress(request), ex);
        return ResponseEntity.builderResponse(404, ex == null ? null : ex.getMessage(), null);
    }

    @ExceptionHandler(TypeMismatchException.class)
    @ResponseBody
    public ResponseEntity<String> requestTypeMismatch(TypeMismatchException ex) {
        log.error("参数类型有误:{}", ex.getMessage());
        return ResponseEntity.builderResponse(405, "参数类型不匹配,参数" + ex.getPropertyName() + "类型应该为" + ex.getRequiredType(), null);
    }

    @ResponseStatus(code = HttpStatus.INTERNAL_SERVER_ERROR)
    @ExceptionHandler(value = Exception.class)
    public ResponseEntity<Void> handlerException(Exception e) {
        log.error("服务器错误:{}", e.getMessage());
        return ResponseEntity.error();
    }
}
